#include <iostream>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/optional.hpp>
#include <queue>

#include <os/miscellany/stddef.h>
#include <sw/redis++/redis++.h>
#include <sw/redis++/errors.h>

#include <modbus/modbus.h>

#include "CDataUnit.h"
#include "CModbusMap.h"

static std::string getDevSigHashKey(std::string& user, std::string& dev, std::string& name, SDataUnit::SigType type) {

    std::string typebuf;
    if(SDataUnit::SigType::Yx == type) {
        typebuf = "yx";
    } else if(SDataUnit::SigType::Yc == type) {
        typebuf = "yc";
    } else if(SDataUnit::SigType::Yk == type) {
        typebuf = "yk";
    } else {
        typebuf = "parameter";
    }

    std::stringstream ss;
    ss << "userid." << user << ".device." << dev << "." <<typebuf <<"." << name;
    return ss.str();
}

// 命令类型，可以根据需要扩展
typedef SDataUnit Command;
// 执行结果类型，可以根据需要扩展
typedef SDataUnit Result;

// 线程间共享的数据结构
struct SharedData {
    boost::mutex mtx;
    boost::condition_variable cond;
    std::queue<Command> commands;
    boost::optional<Result> result;
    bool has_result = false;

    void enqueue_command(const Command& cmd) {
        boost::lock_guard<boost::mutex> lock(mtx);
        commands.push(cmd);
        cond.notify_one(); // 通知B线程有新命令
    }

    boost::optional<Result> dequeue_result() {
        boost::unique_lock<boost::mutex> lock(mtx);
        cond.wait(lock, [this] { return has_result; }); // 等待结果
        has_result = false; // 重置状态
        return result;
    }

    Command dequeue_command() {
        boost::unique_lock<boost::mutex> lock(mtx);
        cond.wait(lock, [this] { return !commands.empty(); }); // 等待命令
        Command cmd = commands.front();
        commands.pop();
        return cmd;
    }

    void enqueue_result(const Result& res) {
        boost::lock_guard<boost::mutex> lock(mtx);
        result = res;
        has_result = true;
        cond.notify_one(); // 通知A线程有结果
    }
};

// A线程的工作函数
void thread_A_function(boost::shared_ptr<SharedData> shared_data) {
    CModbusMap* map = new CModbusMap("admin.step_motor.dasda", "step_motor");

    // 连接到 Redis 服务器
    GET_REDIS_HANDLE;
    std::string queueName = "my_queue";
    if (!redis->exists(queueName)) {
        redis->lpush(queueName, "this is test element!");
    }
    // 无限循环，非阻塞地读取队列中的元素
    int addr = 0;
    bool change = false;
    while (true) {
        // 使用 BRPOP 命令非阻塞地读取队列中的元素，超时设置为 0 表示立即返回
        auto result = redis->rpop(queueName);
        if (result) {
            // 读取成功，获取元素
            std::string element = result->c_str();
            std::cout << "Read element from queue: " << element << std::endl;
        } else {
            SDataUnit unit = map->getCurrCallUnit();
            Command cmd;
            cmd.regtype = unit.regtype;
            cmd.sigtype = unit.sigtype;
            cmd.ctltype = SDataUnit::Read;
            cmd.saddress = unit.saddress;
            shared_data->enqueue_command(cmd);
            boost::optional<Result> rres = shared_data->dequeue_result();
            if (rres) {
                if (rres->valid) {
                    std::string key = getDevSigHashKey(unit.user, unit.dev, unit.name, unit.sigtype);
                    redis->hset(key,"v", std::to_string(rres->reg));
                    std::cout << "name=" << unit.name <<",read addr=" << rres->saddress << ", value = " << rres->reg << std::endl;
                }
            }
        }
    }
}
// B线程的工作函数
void thread_B_function(boost::shared_ptr<SharedData> shared_data) {
    modbus_t *ctx = modbus_new_tcp("192.168.56.1", 1502); // 替换为你的Modbus服务器IP和端口
    if (ctx == NULL) {
        fprintf(stderr, "Unable to create the libmodbus context\n");
        exit(-1);
    }

    // 连接到Modbus服务器
    if (modbus_connect(ctx) == -1) {
        fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
        modbus_free(ctx);
        exit(-1);
    }

    modbus_set_slave(ctx, 1);

    while (true) { // 假设B线程一直运行
        Command cmd = shared_data->dequeue_command();
        Result res = cmd;
        if(cmd.ctltype == SDataUnit::Read) {
            switch (cmd.regtype) {
                case SDataUnit::DiscreteInputs:{
                    uint8_t bit = 0;
                    if(-1 == modbus_read_input_bits(ctx, cmd.saddress, 1, &bit)) {
                        res.valid = false;
                    } else {
                        res.reg = bit;
                        res.valid = true;
                    }
                } break;
                case SDataUnit::Coils: {
                    uint8_t bit = 0;
                    if(-1 == modbus_read_bits(ctx, cmd.saddress, 1, &bit)) {
                        res.valid = false;
                    } else {
                        res.reg = bit;
                        res.valid = true;
                    }
                }break;
                case SDataUnit::InputRegisters: {
                    if (-1 == modbus_read_input_registers(ctx, cmd.saddress, 1, &res.reg)) {
                        res.valid = false;
                    } else {
                        res.valid = true;
                    }
                }break;
                case SDataUnit::HoldingRegisters: {
                    if (-1 == modbus_read_registers(ctx, cmd.saddress, 1, &res.reg)) {
                        res.valid = false;
                    } else {
                        res.valid = true;
                    }
                }break;
                default:
                    res.valid = false;
                    break;
            }
        } else {
            switch (cmd.regtype) {
                case SDataUnit::Coils: {
                    uint8_t bit = 0;
                    if(-1 == modbus_write_bit(ctx, cmd.saddress, cmd.reg)) {
                        res.valid = false;
                    } else {
                        res.valid = true;
                    }
                }break;
                case SDataUnit::HoldingRegisters: {
                    if (-1 == modbus_write_register(ctx, cmd.saddress,cmd.reg)) {
                        res.valid = false;
                    } else {
                        res.valid = true;
                    }
                }break;
                default:
                    res.valid = false;
                break;
            }
        }
        shared_data->enqueue_result(res);
    }
}

int main() {
    // 创建共享数据

    boost::shared_ptr<SharedData> shared_data = boost::make_shared<SharedData>();
    // 创建线程
    boost::thread thread_A(thread_A_function, shared_data);
    boost::thread thread_B(thread_B_function, shared_data);

    // 等待线程完成（在实际应用中，可能需要更复杂的线程管理）
    thread_A.join();
    thread_B.join();

    return 0;
}

